package com.cryptoneedle.garden.service.garden.source;


import com.cryptoneedle.garden.constant.CommonConstant;
import com.cryptoneedle.garden.constant.SourceConstant;
import com.cryptoneedle.garden.entity.source.metadata.SourceCatalog;
import com.cryptoneedle.garden.entity.source.metadata.SourceColumn;
import com.cryptoneedle.garden.entity.source.metadata.SourceTable;
import com.cryptoneedle.garden.enums.DorisDataType;
import com.cryptoneedle.garden.service.crud.garden.source.*;
import com.cryptoneedle.garden.service.garden.config.ConfigPropertyService;
import com.cryptoneedle.garden.service.properties.DorisProperties;
import com.cryptoneedle.garden.service.util.ConfigUtil;
import com.cryptoneedle.garden.service.util.CryptoUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>description:  </p>
 *
 * @author CryptoNeedle
 * @date 2025-10-23
 */
@Slf4j
@Service
@Transactional
public class ScriptService {

    @Resource
    private ScriptService scriptService;

    @Autowired
    private FoundSourceService select;
    @Autowired
    private AddSourceService add;
    @Autowired
    private PatchSourceService patch;
    @Autowired
    private SaveSourceService save;
    @Autowired
    private DeleteSourceService delete;

    @Resource
    private ConfigPropertyService configPropertyService;

    @Resource
    private DorisProperties dorisProperties;
    @Resource
    private ConfigUtil configUtil;


    public String dorisScript(String catalogName, String databaseName, String tableName) {
        SourceCatalog catalog = select.catalog(catalogName);
        SourceTable table = select.table(catalogName, databaseName, tableName);

        return new StringBuilder().append(scriptService.createCatalog(catalog, false))
                .append("\n")
                .append(scriptService.dropTable(table))
                .append("\n")
                .append(scriptService.createTable(table))
                .append("\n")
                .append(scriptService.selectCountTable(table))
                .append("\n")
                .append(scriptService.selectTable(table))
                .append("\n")
                .toString();
    }

    public String createCatalog(SourceCatalog catalog, boolean test) {
        String dorisCatalogName = catalog.getDorisCatalogName();
        if (StringUtils.isBlank(dorisCatalogName)) {
            throw new RuntimeException("[Source] " + catalog.getCatalogName() + " -> CREATE CATALOG -> 异常 => dorisCatalogName=" + dorisCatalogName);
        }

        String catalogName = (test ? SourceConstant.TEST_CATALOG_PREFIX : "") + dorisCatalogName;

        return String.format("""
                        CREATE CATALOG IF NOT EXISTS `%s` COMMENT '%s'
                        PROPERTIES (
                            "type"="jdbc",
                            "driver_url" = "%s",
                            "driver_class" = "%s",
                            "jdbc_url" = "%s",
                            "user"="%s",
                            "password"="%s",
                            "lower_case_meta_names" = "false",
                            "meta_names_mapping" = "",
                            "only_specified_database" = "false",
                            "include_database_list" = "",
                            "exclude_database_list" = "",
                            "connection_pool_min_size" = "%d",
                            "connection_pool_max_size" = "%d",
                            "connection_pool_max_wait_time" = "%d",
                            "connection_pool_max_life_time" = "%d",
                            "connection_pool_keep_alive" = "%b",
                            "enable.auto.analyze" ="false"
                        );"""
                , catalogName
                , catalog.getCatalogName()
                , dorisProperties.getDriverJar(catalog.getDatabaseType())
                , dorisProperties.getDriverClass(catalog.getDatabaseType())
                , catalog.getUrl()
                , catalog.getUserName()
                , CryptoUtils.decrypt(catalog.getPassword())
                , dorisProperties.getCatalog().getConnectionPool().getMinSize()
                , dorisProperties.getCatalog().getConnectionPool().getMaxSize()
                , dorisProperties.getCatalog().getConnectionPool().getMaxWaitTime()
                , dorisProperties.getCatalog().getConnectionPool().getMaxLifeTime()
                , dorisProperties.getCatalog().getConnectionPool().getKeepAlive()
        );
    }

    public String selectTable(SourceTable table) {
        return "SELECT * FROM %s.%s;".formatted(configUtil.ods(), table.getTransTableName());
    }

    public String selectCountTable(SourceTable table) {
        return "SELECT count(*) FROM %s.%s; -- %s".formatted(configUtil.ods(), table.getTransTableName(), table.getRowCount());
    }

    public String dropTable(SourceTable table) {
        return "DROP TABLE IF EXISTS %s.%s;".formatted(configUtil.ods(), table.getTransTableName());
    }

    public String createTable(SourceTable table) {
        String template = CommonConstant.CREATE_TABLE_TEMPLATE;

        String ods = configUtil.ods();
        String tableName = table.getTransTableName();
        String columnDefinition = columnDefinitions(table);
        String uniqueKeys = uniqueKeys(table);
        Integer bucket = table.getTransBucketCount();
        String comment = table.getTransComment();
        return template.formatted(ods, tableName, columnDefinition, uniqueKeys, comment, uniqueKeys, bucket);
    }

    public String uniqueKeys(SourceTable table) {
        return select.columnsWithDimension(table).stream().map(SourceColumn::getTransColumnName).collect(Collectors.joining(","));
    }

    public String columnDefinitions(SourceTable table) {
        // 维度列（需要优先级）
        List<SourceColumn> dimensions = select.columnsWithDimension(table);
        // 非维度列
        List<SourceColumn> columns = select.columnsWithoutDimension(table);

        // 列总量
        int columnCount = dimensions.size() + columns.size();

        // 构造列表
        List<String> columnNames = new ArrayList<>(columnCount);
        List<String> columnTypes = new ArrayList<>(columnCount);
        List<String> columnComments = new ArrayList<>(columnCount);
        for (SourceColumn column : dimensions) {
            columnNames.add(column.getTransColumnName());
            columnTypes.add(column.transFullDataType());
            columnComments.add(column.getTransComment());
        }
        for (SourceColumn column : columns) {
            columnNames.add(column.getTransColumnName());
            columnTypes.add(column.transFullDataType());
            columnComments.add(column.getTransComment());
        }

        // 构造 gather_time
        columnNames.add("gather_time");
        columnTypes.add(DorisDataType.DATETIME.toString());
        columnComments.add("采集时间");

        // 计算最大长度（用于格式化）
        int maxColumnName = columnNames.stream().mapToInt(String::length).max().orElse(0);
        int maxColumnType = columnTypes.stream().mapToInt(String::length).max().orElse(0);

        StringBuilder columnDefinition = new StringBuilder();
        for (int i = 0; i < columnCount; i++) {
            String columnName = columnNames.get(i);
            String columnType = columnNames.get(i);
            String columnComment = columnNames.get(i);
            if (i < columnCount - 1) {
                columnDefinition.append(("    %-" + maxColumnName + "s %-" + maxColumnType + "s COMMENT '%s',\n").formatted(columnName, columnType, columnComment));
            } else {
                // gather_time
                columnDefinition.append(("    %-" + maxColumnName + "s %-" + maxColumnType + "s DEFAULT CURRENT_TIMESTAMP COMMENT '%s'").formatted(columnName, columnType, columnComment));
            }
        }
        return columnDefinition.toString();
    }

    public void generateDolphinSchedulerTask(String catalogName, String databaseName) {

    }
}